package com.assistant.audio;

import ai.picovoice.porcupine.Porcupine; // 【新增】
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sound.sampled.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.function.Consumer;

/**
 * @author Anyang
 * @version 1.0.0
 * @date 2025/10/25 05:10:23
 * @description 音频输入模块：捕获音频数据并传递给 Porcupine/Cobra
 */
public class MicrophoneModule {

    private static final Logger logger = LoggerFactory.getLogger(MicrophoneModule.class);

    // 音频格式必须与 Porcupine/Cobra 匹配: 16kHz, 16-bit, 单声道, PCM
    private static final float SAMPLE_RATE = 16000;
    private static final int SAMPLE_SIZE_IN_BITS = 16;
    private static final int CHANNELS = 1; // 单声道
    private static final boolean SIGNED = true;
    private static final boolean BIG_ENDIAN = false;

    private final AudioFormat audioFormat = new AudioFormat(
            SAMPLE_RATE,
            SAMPLE_SIZE_IN_BITS,
            CHANNELS,
            SIGNED,
            BIG_ENDIAN
    );

    private TargetDataLine targetDataLine;
    private Thread captureThread;
    private volatile boolean isCapturing = false;

    // 【新增】音频消费者接口，用于 MainApplication 接收数据
    private final Consumer<short[]> audioFrameConsumer;
    // 【新增】Porcupine 要求的帧长度 (例如 512 个采样点)
    private final int frameLength;

    /**
     * 【修改】构造函数需要 Porcupine 实例来获取帧长度
     */
    public MicrophoneModule(Porcupine porcupine, Consumer<short[]> audioFrameConsumer) {
        this.audioFrameConsumer = audioFrameConsumer;
        this.frameLength = porcupine.getFrameLength(); // Porcupine 决定了我们一次读多少
    }

    /**
     * 【新增】开始实时音频流捕获
     */
    public boolean startStreaming() {
        if (isCapturing) {
            logger.warn("音频流已在捕获中，请勿重复启动。");
            return false;
        }

        try {
            DataLine.Info info = new DataLine.Info(TargetDataLine.class, audioFormat);
            if (!AudioSystem.isLineSupported(info)) {
                logger.error("系统不支持指定的音频格式：{}。", audioFormat);
                return false;
            }

            targetDataLine = (TargetDataLine) AudioSystem.getLine(info);
            // 【修改】缓冲区大小应至少为帧长度的几倍
            targetDataLine.open(audioFormat, frameLength * 10);
            targetDataLine.start();

            isCapturing = true;

            // 启动捕获线程
            captureThread = new Thread(this::captureLoop, "Audio-Capture-Thread");
            captureThread.start();
            logger.info("【麦克风】已启动实时音频流，帧长度: {}", frameLength);
            return true;

        } catch (LineUnavailableException e) {
            logger.error("麦克风不可用，请检查设备连接和权限设置: {}", e.getMessage(), e);
            isCapturing = false;
            return false;
        }
    }

    /**
     * 【新增】音频捕获循环
     */
    private void captureLoop() {
        // 字节缓冲区 (short * 2 bytes/short)
        byte[] byteBuffer = new byte[frameLength * 2];
        // short 缓冲区 (Porcupine/Cobra 需要 short[])
        short[] shortBuffer = new short[frameLength];

        while (isCapturing) {
            try {
                // 1. 从麦克风读取刚好一帧的数据
                int bytesRead = targetDataLine.read(byteBuffer, 0, byteBuffer.length);

                if (bytesRead != byteBuffer.length) {
                    logger.warn("音频读取不足一帧，期望 {} 字节, 实际 {}", byteBuffer.length, bytesRead);
                    continue;
                }

                // 2. 将 bytes 转换为 shorts
                ByteBuffer.wrap(byteBuffer)
                        .order(ByteOrder.LITTLE_ENDIAN)
                        .asShortBuffer()
                        .get(shortBuffer);

                // 3. 将 short[] 帧发送给消费者 (MainApplication)
                if (audioFrameConsumer != null) {
                    audioFrameConsumer.accept(shortBuffer);
                }

            } catch (Exception e) {
                if (isCapturing) {
                    logger.error("音频捕获循环出错", e);
                }
            }
        }
        logger.info("【麦克风】音频捕获线程已停止。");
    }

    /**
     * 【修改】停止音频流
     */
    public void stopStreaming() {
        if (!isCapturing) {
            return;
        }
        logger.info("【麦克风】正在停止音频流...");
        isCapturing = false; // 停止循环

        if (captureThread != null) {
            captureThread.interrupt();
        }
        if (targetDataLine != null) {
            targetDataLine.stop();
            targetDataLine.close();
        }
        logger.info("【麦克风】音频流已停止。");
    }

    public boolean isCapturing() {
        return isCapturing;
    }
}